#include "WProgram.h"
/* * * * * * * * * * * * * * * * * * * 
 GPS-A-Sketch version .06
 TEST PROGRAM FOR BUILDING -- OUTPUTS NMEA DATA VIA FTDI SERIAL TO TERMINAL
 ALSO OUTPUTS UTC,LAT & LON TO LCD
 & TEST STRINGS FOR BUTTON A & BUTTON B
 
 Project started August, 2008
 by Wil Lindsay
 For the Hacktory  
 http://thehacktory.org
 
 NMEA read code based loosely on code by 
 Igor Gonz\u00e1lez Mart\u00edn from 05-04-2007   
 
 * * * * * * * * * * * * * * * * * * */

#include <SoftwareSerial.h>
#include <string.h>
#include <ctype.h>

#define buttonPinA 3
#define buttonPinB 4
#define LCDrxPin 5
#define LCDtxPin 6
#define ledPin 13
#define GPStxPin 7
#define GPSrxPin 8

// set up 2 new serial ports for LCD and GPS
void setup();
void loop();
int NMEA_fieldSize(int fieldNumber);
void toggle(int pinNum);
void LCD_init();
void LCD_line(int x1,int y1,int x2,int y2);
void LCD_wake();
void LCD_sleep();
SoftwareSerial LCDSerial =  SoftwareSerial(LCDrxPin, LCDtxPin);
SoftwareSerial GPSSerial =  SoftwareSerial(GPSrxPin, GPStxPin);

byte pinState = 0;
byte buttonStateA = 0;
byte buttonStateB = 0;

int byteGPS=-1;
char NMEA_buffer[300] = "";                          //buffer for NMEA data
char NMEA_header[7] = "$GPRMC";
int cont=0;
int bien=0;
int conta=0;
int indices[12];

void setup() {
  // define pin modes for GPS, LCD & led pins:
  pinMode(buttonPinA, INPUT);
  pinMode(buttonPinB, INPUT);
  pinMode(LCDrxPin, INPUT);
  pinMode(LCDtxPin, OUTPUT);
  pinMode(GPSrxPin, INPUT);
  pinMode(GPStxPin, OUTPUT);
  pinMode(ledPin, OUTPUT);

  // set the data rate for the SoftwareSerial port
  LCDSerial.begin(9600);
  GPSSerial.begin(4800);
  //initialize SGD_A LCD unit
  LCD_init();

  Serial.begin(9600);
  for (int i=0;i<300;i++){       // Initialize a buffer for received data
    NMEA_buffer[i]=' ';
  }  
}

void loop() {
  digitalWrite(ledPin, LOW);
  byteGPS=GPSSerial.read();         // Read a byte from the serial port
  if (byteGPS == -1) {              // See if the port is empty
    delay(100); 
  } 
  else {
    NMEA_buffer[conta]=byteGPS;        // If there is serial port data, put it in the buffer
    conta++;                      
    if (byteGPS==13){            // If the received byte is = to 13, end of transmission
      digitalWrite(ledPin, HIGH); 
      cont=0;
      bien=0;
      for (int i=1;i<7;i++){     // Verifies if the received command starts with $GPRMC header
        if (NMEA_buffer[i]==NMEA_header[i-1]){
          bien++;
        }
      }
      if(bien==6){               // If yes, continue and process the data
        for (int i=0;i<300;i++){
          if (NMEA_buffer[i]==','){    // check for the position of the  "," separator
            indices[cont]=i;
            cont++;
          }
          if (NMEA_buffer[i]=='*'){      //check for the * -- starting checksum
            indices[11]=i+3;
            cont++;
          }
        }
        Serial.println("");      // ... and write to the serial port
        Serial.println("");
        Serial.println("---------------");
        for (int i=0;i<11;i++){
         switch(i){
          case 0 :
            Serial.print("Time in UTC (HhMmSs): ");
            delay(100);                                                      //Clear LCD & send UTC to LCD
            LCDSerial.print('N',BYTE);               //clear screen
            delay(100);
            LCDSerial.print('S',BYTE);               
            LCDSerial.print(NMEA_fieldSize(i)+7,BYTE);
            LCDSerial.print("Time:");
            LCDSerial.print(10,BYTE);                //Linefeed
            for (int j=indices[i];j<(indices[i+1]-1);j++){
              LCDSerial.print(NMEA_buffer[j+1]);
            }
            LCDSerial.print(10,BYTE);                //Linefeed
            break;
          case 1 :
            Serial.print("Status (A=OK,V=KO): ");
            break;
          case 2 :
            Serial.print("Latitude: ");
            delay(100);                                              //send LATITUDE to LCD
            LCDSerial.print('S',BYTE);               
            LCDSerial.print(NMEA_fieldSize(i)+6,BYTE);
            LCDSerial.print("LAT:");
            LCDSerial.print(10,BYTE);                //Linefeed
            for (int j=indices[i];j<(indices[i+1]-1);j++){
              LCDSerial.print(NMEA_buffer[j+1]);
            }
            LCDSerial.print(10,BYTE);                //Linefeed
            break;
          case 3 :
            Serial.print("Direction (N/S): ");
            break;
          case 4 :
            Serial.print("Longitude: ");
            delay(100);                                        //send LONGITUDE to LCD
            LCDSerial.print('S',BYTE);               
            LCDSerial.print(NMEA_fieldSize(i)+5,BYTE);
            LCDSerial.print("LON:");
            LCDSerial.print(10,BYTE);                //Linefeed
            for (int j=indices[i];j<(indices[i+1]-1);j++){
              LCDSerial.print(NMEA_buffer[j+1]);
            }
            break;
          case 5 :
            Serial.print("Direction (E/W): ");
            break;
          case 6 :
            Serial.print("Velocity in knots: ");
            break;
          case 7 :
            Serial.print("Heading in degrees: ");
            break;
          case 8 :
            Serial.print("Date UTC (DdMmAa): ");
            break;
          case 9 :
            Serial.print("Magnetic Var: ");
            break;
          case 10 :
            Serial.print("Checksum: ");
            break;
          }
          for (int j=indices[i];j<(indices[i+1]-1);j++){
            Serial.print(NMEA_buffer[j+1]); 
          }
          Serial.println("");
        }
        Serial.println("---------------");
      }
      conta=0;                    // Reset the buffer
      for (int i=0;i<300;i++){    //  
        NMEA_buffer[i]=' ';             
      }                 
    }
  }
  
  //* * * * * * * * Button tests * * * * * * * *
  buttonStateA = digitalRead(buttonPinA);
  buttonStateB = digitalRead(buttonPinB);
  if (buttonStateA == HIGH || buttonStateB == HIGH){
      if (buttonStateA == HIGH){
        delay(100);
        LCDSerial.print('N',BYTE);               //clear screen
        delay(100);
        LCDSerial.print('S',BYTE);               //print ButtonA
        LCDSerial.print(8,BYTE);
        LCDSerial.print("Button A");
        buttonStateA = LOW;
      } 
      if (buttonStateB == HIGH){
        delay(100);
        LCDSerial.print('N',BYTE);               //clear screen
        delay(100);
        LCDSerial.print('S',BYTE);               //print printButtonB
        LCDSerial.print(8,BYTE);
        LCDSerial.print("Button B");
        buttonStateB = LOW;
      } 
  }
  
//* * * * * * * End Button tests * * * * * * * *
}

//********************************NMEA data parser
/*  as follows:  

case : content : format : fieldsize used

  0:  Time in UTC             : HhMmSs.sss         : 10
  1:  Status (A=OK,V=KO)      : A or V             : 1
  2:  Latitude                : ddmm.mmmm          : 9
  3:  Direction (N/S)         : N or S             : 1
  4:  Longitude               : dddmm.mmmm         : 10
  5:  Direction (E/W)         : E or W             : 1
  6:  Velocity in knots       : k.kk               : 4
  7:  Heading in degrees      : ddd.dd             : 6
  8:  Date UTC                : DdMmYy             : 6
  9:  Magnetic Var deg. (E/W) : none               : 0          // Mag Var not on EM-406A & no "Mode" sent
  10: CheckSum                : *Dd                : 3          // Message terminated with <CR> <LF> (ASCII <10><13>)

*/


//********************************array Field Size for NMEA field data
int NMEA_fieldSize(int fieldNumber) {
 return (indices[fieldNumber+1]-indices[fieldNumber]-1);     //how many spaces between the commas
}
  


//********************************toggle function for the LED
void toggle(int pinNum) {
  // set the LED pin using the pinState variable:
  digitalWrite(pinNum, pinState); 
  // if pinState = 0, set it to 1, and vice versa:
  pinState = !pinState;
}

// ******************************* SGD-A LCD initialization

void LCD_init(){
  toggle(13);
  delay(1000);       //sleep & awake to initialize LCD system
  LCD_sleep();
  delay(1000);
  LCD_wake();
  delay(100);
  LCDSerial.print('N',BYTE);               //clear screen
  delay(100);
  LCDSerial.print('S',BYTE);               //print logo
  LCDSerial.print(18,BYTE);
  LCDSerial.print("GPS-A-Sketch! v.01");

  delay(100);
  LCDSerial.print('T',BYTE);               //2 tone chirp
  LCDSerial.print(51,BYTE);
  LCDSerial.print(12,BYTE);
  LCDSerial.print(2,BYTE);
  delay(100);
  LCDSerial.print('T',BYTE);
  LCDSerial.print(12,BYTE);
  LCDSerial.print(249,BYTE);
  LCDSerial.print(2,BYTE);
  delay (1000);
  //LCDSerial.print('N',BYTE);               //clear screen
  toggle(13);
}
//********************************Line Function for LCD
void LCD_line(int x1,int y1,int x2,int y2){
  delay(100);
  LCDSerial.print('P',BYTE);            //startpoint x & y
  LCDSerial.print(x1,BYTE);
  LCDSerial.print(y1,BYTE);

  delay(100);
  LCDSerial.print('L',BYTE);            //endpoint x & y
  LCDSerial.print(x2,BYTE);
  LCDSerial.print(y2,BYTE);
  delay(100);


}
//******************************** LCD wake from sleep
void LCD_wake() {
  char result = 'Z';
  do {
    LCDSerial.print('X', BYTE);        //ping command - ping LCD until it responds
    result = LCDSerial.read();
    toggle(13);
  } 
  while (result != 'X') ;           //with an 'X'
}
//*************************to enter LCD sleep mode
void LCD_sleep() {
  LCDSerial.print('Z', BYTE);
}

int main(void)
{
	init();

	setup();
    
	for (;;)
		loop();
        
	return 0;
}

